home *** CD-ROM | disk | FTP | other *** search
/ Aminet 44 / Aminet 44 (2001)(GTI - Schatztruhe)[!][Aug 2001].iso / Aminet / dev / misc / AmigaSDLsrc.lha / amisrc / SDL_surface.c < prev    next >
C/C++ Source or Header  |  2001-04-29  |  21KB  |  821 lines

  1. /*
  2.     SDL - Simple DirectMedia Layer
  3.     Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga
  4.  
  5.     This library is free software; you can redistribute it and/or
  6.     modify it under the terms of the GNU Library General Public
  7.     License as published by the Free Software Foundation; either
  8.     version 2 of the License, or (at your option) any later version.
  9.  
  10.     This library is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13.     Library General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU Library General Public
  16.     License along with this library; if not, write to the Free
  17.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  
  19.     Sam Lantinga
  20.     slouken@devolution.com
  21. */
  22.  
  23. #ifdef SAVE_RCSID
  24. static char rcsid =
  25.  "@(#) $Id: SDL_surface.c,v 1.8.2.32 2001/03/19 19:03:18 hercules Exp $";
  26. #endif
  27.  
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31.  
  32. #include "SDL_error.h"
  33. #include "SDL_video.h"
  34. #include "SDL_sysvideo.h"
  35. #include "SDL_cursor_c.h"
  36. #include "SDL_blit.h"
  37. #include "SDL_RLEaccel_c.h"
  38. #include "SDL_pixels_c.h"
  39. #include "SDL_memops.h"
  40. #include "SDL_leaks.h"
  41.  
  42. /* Public routines */
  43. /*
  44.  * Create an empty RGB surface of the appropriate depth
  45.  */
  46. SDL_Surface * SDL_CreateRGBSurface (Uint32 flags,
  47.             int width, int height, int depth,
  48.             Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
  49. {
  50.     SDL_VideoDevice *video = current_video;
  51.     SDL_VideoDevice *this  = current_video;
  52.     SDL_Surface *screen;
  53.     SDL_Surface *surface;
  54.  
  55.     /* Check to see if we desire the surface in video memory */
  56.     if ( video ) {
  57.         screen = SDL_PublicSurface;
  58.     } else {
  59.         screen = NULL;
  60.     }
  61.     if ( screen && ((screen->flags&SDL_HWSURFACE) == SDL_HWSURFACE) ) {
  62.         if ( (flags&(SDL_SRCCOLORKEY|SDL_SRCALPHA)) != 0 ) {
  63.             flags |= SDL_HWSURFACE;
  64.         }
  65.         if ( (flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY ) {
  66.             if ( ! current_video->info.blit_hw_CC ) {
  67.                 flags &= ~SDL_HWSURFACE;
  68.             }
  69.         }
  70.         if ( (flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
  71.             if ( ! current_video->info.blit_hw_A ) {
  72.                 flags &= ~SDL_HWSURFACE;
  73.             }
  74.         }
  75.     } else {
  76.         flags &= ~SDL_HWSURFACE;
  77.     }
  78.  
  79.     /* Allocate the surface */
  80.     surface = (SDL_Surface *)malloc(sizeof(*surface));
  81.     if ( surface == NULL ) {
  82.         SDL_OutOfMemory();
  83.         return(NULL);
  84.     }
  85.     surface->flags = SDL_SWSURFACE;
  86.     if ( (flags & SDL_HWSURFACE) == SDL_HWSURFACE ) {
  87.         depth = screen->format->BitsPerPixel;
  88.         Rmask = screen->format->Rmask;
  89.         Gmask = screen->format->Gmask;
  90.         Bmask = screen->format->Bmask;
  91.         Amask = screen->format->Amask;
  92.     }
  93.     surface->format = SDL_AllocFormat(depth, Rmask, Gmask, Bmask, Amask);
  94.     if ( surface->format == NULL ) {
  95.         free(surface);
  96.         return(NULL);
  97.     }
  98.     if ( Amask ) {
  99.         surface->flags |= SDL_SRCALPHA;
  100.     }
  101.     surface->w = width;
  102.     surface->h = height;
  103.     surface->pitch = SDL_CalculatePitch(surface);
  104.     surface->pixels = NULL;
  105.     surface->offset = 0;
  106.     surface->hwdata = NULL;
  107.     surface->locked = 0;
  108.     surface->map = NULL;
  109.     surface->format_version = 0;
  110.     SDL_SetClipRect(surface, NULL);
  111.  
  112.     /* Get the pixels */
  113.     if ( ((flags&SDL_HWSURFACE) == SDL_SWSURFACE) || 
  114.                 (video->AllocHWSurface(this, surface) < 0) ) {
  115.         if ( surface->w && surface->h ) {
  116.             surface->pixels = malloc(surface->h*surface->pitch);
  117.             if ( surface->pixels == NULL ) {
  118.                 SDL_FreeSurface(surface);
  119.                 SDL_OutOfMemory();
  120.                 return(NULL);
  121.             }
  122.             /* This is important for bitmaps */
  123.             memset(surface->pixels, 0, surface->h*surface->pitch);
  124.         }
  125.     }
  126.  
  127.     /* Allocate an empty mapping */
  128.     surface->map = SDL_AllocBlitMap();
  129.     if ( surface->map == NULL ) {
  130.         SDL_FreeSurface(surface);
  131.         return(NULL);
  132.     }
  133.  
  134.     /* The surface is ready to go */
  135.     surface->refcount = 1;
  136. #ifdef CHECK_LEAKS
  137.     ++surfaces_allocated;
  138. #endif
  139.     return(surface);
  140. }
  141. /*
  142.  * Create an RGB surface from an existing memory buffer
  143.  */
  144. SDL_Surface * SDL_CreateRGBSurfaceFrom (void *pixels,
  145.             int width, int height, int depth, int pitch,
  146.             Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
  147. {
  148.     SDL_Surface *surface;
  149.  
  150.     surface = SDL_CreateRGBSurface(SDL_SWSURFACE, 0, 0, depth,
  151.                                    Rmask, Gmask, Bmask, Amask);
  152.     if ( surface != NULL ) {
  153.         surface->flags |= SDL_PREALLOC;
  154.         surface->pixels = pixels;
  155.         surface->w = width;
  156.         surface->h = height;
  157.         surface->pitch = pitch;
  158.         SDL_SetClipRect(surface, NULL);
  159.     }
  160.     return(surface);
  161. }
  162. /*
  163.  * Set the color key in a blittable surface
  164.  */
  165. int SDL_SetColorKey (SDL_Surface *surface, Uint32 flag, Uint32 key)
  166. {
  167.     /* Sanity check the flag as it gets passed in */
  168.     if ( flag & SDL_SRCCOLORKEY ) {
  169.         if ( flag & (SDL_RLEACCEL|SDL_RLEACCELOK) ) {
  170.             flag = (SDL_SRCCOLORKEY | SDL_RLEACCELOK);
  171.         } else {
  172.             flag = SDL_SRCCOLORKEY;
  173.         }
  174.     } else {
  175.         flag = 0;
  176.     }
  177.  
  178.     /* Optimize away operations that don't change anything */
  179.     if ( (flag == (surface->flags & (SDL_SRCCOLORKEY|SDL_RLEACCELOK))) &&
  180.          (key == surface->format->colorkey) ) {
  181.         return(0);
  182.     }
  183.  
  184.     /* UnRLE surfaces before we change the colorkey */
  185.     if ( surface->flags & SDL_RLEACCEL ) {
  186.             SDL_UnRLESurface(surface, 1);
  187.     }
  188.  
  189.     if ( flag ) {
  190.         SDL_VideoDevice *video = current_video;
  191.         SDL_VideoDevice *this  = current_video;
  192.  
  193.  
  194.         surface->flags |= SDL_SRCCOLORKEY;
  195.         surface->format->colorkey = key;
  196.         if ( (surface->flags & SDL_HWACCEL) == SDL_HWACCEL ) {
  197.             if ( (video->SetHWColorKey == NULL) ||
  198.                  (video->SetHWColorKey(this, surface, key) < 0) ) {
  199.                 surface->flags &= ~SDL_HWACCEL;
  200.             }
  201.         }
  202.         if ( flag & SDL_RLEACCELOK ) {
  203.             surface->flags |= SDL_RLEACCELOK;
  204.         } else {
  205.             surface->flags &= ~SDL_RLEACCELOK;
  206.         }
  207.     } else {
  208.         surface->flags &= ~(SDL_SRCCOLORKEY|SDL_RLEACCELOK);
  209.         surface->format->colorkey = 0;
  210.     }
  211.     SDL_InvalidateMap(surface->map);
  212.     return(0);
  213. }
  214. int SDL_SetAlpha (SDL_Surface *surface, Uint32 flag, Uint8 value)
  215. {
  216.     Uint32 oldflags = surface->flags;
  217.     Uint32 oldalpha = surface->format->alpha;
  218.  
  219.     /* Sanity check the flag as it gets passed in */
  220.     if ( flag & SDL_SRCALPHA ) {
  221.         if ( flag & (SDL_RLEACCEL|SDL_RLEACCELOK) ) {
  222.             flag = (SDL_SRCALPHA | SDL_RLEACCELOK);
  223.         } else {
  224.             flag = SDL_SRCALPHA;
  225.         }
  226.     } else {
  227.         flag = 0;
  228.     }
  229.  
  230.     /* Optimize away operations that don't change anything */
  231.     if ( (flag == (surface->flags & (SDL_SRCALPHA|SDL_RLEACCELOK))) &&
  232.          (!flag || value == oldalpha) ) {
  233.         return(0);
  234.     }
  235.  
  236.     if(!(flag & SDL_RLEACCELOK) && (surface->flags & SDL_RLEACCEL))
  237.         SDL_UnRLESurface(surface, 1);
  238.  
  239.     if ( flag ) {
  240.         SDL_VideoDevice *video = current_video;
  241.         SDL_VideoDevice *this  = current_video;
  242.  
  243.         surface->flags |= SDL_SRCALPHA;
  244.         surface->format->alpha = value;
  245.         if ( (surface->flags & SDL_HWACCEL) == SDL_HWACCEL ) {
  246.             if ( (video->SetHWAlpha == NULL) ||
  247.                  (video->SetHWAlpha(this, surface, value) < 0) ) {
  248.                 surface->flags &= ~SDL_HWACCEL;
  249.             }
  250.         }
  251.         if ( flag & SDL_RLEACCELOK ) {
  252.                 surface->flags |= SDL_RLEACCELOK;
  253.         } else {
  254.                 surface->flags &= ~SDL_RLEACCELOK;
  255.         }
  256.     } else {
  257.         surface->flags &= ~SDL_SRCALPHA;
  258.         surface->format->alpha = SDL_ALPHA_OPAQUE;
  259.     }
  260.     /*
  261.      * The representation for software surfaces is independent of
  262.      * per-surface alpha, so no need to invalidate the blit mapping
  263.      * if just the alpha value was changed. (If either is 255, we still
  264.      * need to invalidate.)
  265.      */
  266.     if((surface->flags & SDL_HWACCEL) == SDL_HWACCEL
  267.        || oldflags != surface->flags
  268.        || (((oldalpha + 1) ^ (value + 1)) & 0x100))
  269.         SDL_InvalidateMap(surface->map);
  270.     return(0);
  271. }
  272.  
  273. /*
  274.  * A function to calculate the intersection of two rectangles:
  275.  * return true if the rectangles intersect, false otherwise
  276.  */
  277. static __inline__
  278. SDL_bool SDL_IntersectRect(SDL_Rect *A, SDL_Rect *B, SDL_Rect *intersection)
  279. {
  280.     int Amin, Amax, Bmin, Bmax;
  281.  
  282.     /* Horizontal intersection */
  283.     Amin = A->x;
  284.     Amax = Amin + A->w;
  285.     Bmin = B->x;
  286.     Bmax = Bmin + B->w;
  287.     if(Bmin > Amin)
  288.             Amin = Bmin;
  289.     intersection->x = Amin;
  290.     if(Bmax < Amax)
  291.             Amax = Bmax;
  292.     intersection->w = Amax - Amin > 0 ? Amax - Amin : 0;
  293.  
  294.     /* Vertical intersection */
  295.     Amin = A->y;
  296.     Amax = Amin + A->h;
  297.     Bmin = B->y;
  298.     Bmax = Bmin + B->h;
  299.     if(Bmin > Amin)
  300.             Amin = Bmin;
  301.     intersection->y = Amin;
  302.     if(Bmax < Amax)
  303.             Amax = Bmax;
  304.     intersection->h = Amax - Amin > 0 ? Amax - Amin : 0;
  305.  
  306.     return (intersection->w && intersection->h);
  307. }
  308. /*
  309.  * Set the clipping rectangle for a blittable surface
  310.  */
  311. SDL_bool SDL_SetClipRect(SDL_Surface *surface, SDL_Rect *rect)
  312. {
  313.     SDL_Rect full_rect;
  314.  
  315.     /* Don't do anything if there's no surface to act on */
  316.     if ( ! surface ) {
  317.         return SDL_FALSE;
  318.     }
  319.  
  320.     /* Set up the full surface rectangle */
  321.     full_rect.x = 0;
  322.     full_rect.y = 0;
  323.     full_rect.w = surface->w;
  324.     full_rect.h = surface->h;
  325.  
  326.     /* Set the clipping rectangle */
  327.     if ( ! rect ) {
  328.         surface->clip_rect = full_rect;
  329.         return 1;
  330.     }
  331.     return SDL_IntersectRect(rect, &full_rect, &surface->clip_rect);
  332. }
  333. void SDL_GetClipRect(SDL_Surface *surface, SDL_Rect *rect)
  334. {
  335.     if ( surface && rect ) {
  336.         *rect = surface->clip_rect;
  337.     }
  338. }
  339. /* 
  340.  * Set up a blit between two surfaces -- split into three parts:
  341.  * The upper part, SDL_UpperBlit(), performs clipping and rectangle 
  342.  * verification.  The lower part is a pointer to a low level
  343.  * accelerated blitting function.
  344.  *
  345.  * These parts are separated out and each used internally by this 
  346.  * library in the optimimum places.  They are exported so that if
  347.  * you know exactly what you are doing, you can optimize your code
  348.  * by calling the one(s) you need.
  349.  */
  350. int SDL_LowerBlit (SDL_Surface *src, SDL_Rect *srcrect,
  351.                 SDL_Surface *dst, SDL_Rect *dstrect)
  352. {
  353.     SDL_blit do_blit;
  354.  
  355.     /* Check to make sure the blit mapping is valid */
  356.     if ( (src->map->dst != dst) ||
  357.              (src->map->dst->format_version != src->map->format_version) ) {
  358.         if ( SDL_MapSurface(src, dst) < 0 ) {
  359.             return(-1);
  360.         }
  361.     }
  362.  
  363.     /* Figure out which blitter to use */
  364.     if ( (src->flags & SDL_HWACCEL) == SDL_HWACCEL ) {
  365.         do_blit = src->map->hw_blit;
  366.     } else {
  367.         do_blit = src->map->sw_blit;
  368.     }
  369.     return(do_blit(src, srcrect, dst, dstrect));
  370. }
  371.  
  372.  
  373. int SDL_UpperBlit (SDL_Surface *src, SDL_Rect *srcrect,
  374.            SDL_Surface *dst, SDL_Rect *dstrect)
  375. {
  376.         SDL_Rect fulldst;
  377.     int srcx, srcy, w, h;
  378.  
  379.     /* Make sure the surfaces aren't locked */
  380.     if ( ! src || ! dst ) {
  381.         SDL_SetError("SDL_UpperBlit: passed a NULL surface");
  382.         return(-1);
  383.     }
  384.     if ( src->locked || dst->locked ) {
  385.         SDL_SetError("Surfaces must not be locked during blit");
  386.         return(-1);
  387.     }
  388.  
  389.     /* If the destination rectangle is NULL, use the entire dest surface */
  390.     if ( dstrect == NULL ) {
  391.             fulldst.x = fulldst.y = 0;
  392.         dstrect = &fulldst;
  393.     }
  394.  
  395.     /* clip the source rectangle to the source surface */
  396.     if(srcrect) {
  397.             int maxw, maxh;
  398.     
  399.         srcx = srcrect->x;
  400.         w = srcrect->w;
  401.         if(srcx < 0) {
  402.                 w += srcx;
  403.             dstrect->x -= srcx;
  404.             srcx = 0;
  405.         }
  406.         maxw = src->w - srcx;
  407.         if(maxw < w)
  408.             w = maxw;
  409.  
  410.         srcy = srcrect->y;
  411.         h = srcrect->h;
  412.         if(srcy < 0) {
  413.                 h += srcy;
  414.             dstrect->y -= srcy;
  415.             srcy = 0;
  416.         }
  417.         maxh = src->h - srcy;
  418.         if(maxh < h)
  419.             h = maxh;
  420.         
  421.     } else {
  422.             srcx = srcy = 0;
  423.         w = src->w;
  424.         h = src->h;
  425.     }
  426.  
  427.     /* clip the destination rectangle against the clip rectangle */
  428.     {
  429.             SDL_Rect *clip = &dst->clip_rect;
  430.         int dx, dy;
  431.  
  432.         dx = clip->x - dstrect->x;
  433.         if(dx > 0) {
  434.             w -= dx;
  435.             dstrect->x += dx;
  436.             srcx += dx;
  437.         }
  438.         dx = dstrect->x + w - clip->x - clip->w;
  439.         if(dx > 0)
  440.             w -= dx;
  441.  
  442.         dy = clip->y - dstrect->y;
  443.         if(dy > 0) {
  444.             h -= dy;
  445.             dstrect->y += dy;
  446.             srcy += dy;
  447.         }
  448.         dy = dstrect->y + h - clip->y - clip->h;
  449.         if(dy > 0)
  450.             h -= dy;
  451.     }
  452.  
  453.     if(w > 0 && h > 0) {
  454.             SDL_Rect sr;
  455.             sr.x = srcx;
  456.         sr.y = srcy;
  457.         sr.w = dstrect->w = w;
  458.         sr.h = dstrect->h = h;
  459.         return SDL_LowerBlit(src, &sr, dst, dstrect);
  460.     }
  461.     dstrect->w = dstrect->h = 0;
  462.     return 0;
  463. }
  464.  
  465. /* 
  466.  * This function performs a fast fill of the given rectangle with 'color'
  467.  */
  468. int SDL_FillRect(SDL_Surface *dst, SDL_Rect *dstrect, Uint32 color)
  469. {
  470.     SDL_VideoDevice *video = current_video;
  471.     SDL_VideoDevice *this  = current_video;
  472.     int x, y;
  473.     Uint8 *row;
  474.  
  475.     /* If 'dstrect' == NULL, then fill the whole surface */
  476.     if ( dstrect ) {
  477.         /* Perform clipping */
  478.         if ( !SDL_IntersectRect(dstrect, &dst->clip_rect, dstrect) ) {
  479.             return(0);
  480.         }
  481.     } else {
  482.         dstrect = &dst->clip_rect;
  483.     }
  484.  
  485.     /* Check for hardware acceleration */
  486.     if ( ((dst->flags & SDL_HWSURFACE) == SDL_HWSURFACE) &&
  487.                     video->info.blit_fill ) {
  488.         return(video->FillHWRect(this, dst, dstrect, color));
  489.     }
  490.  
  491.     /* Perform software fill */
  492.     if ( SDL_LockSurface(dst) != 0 ) {
  493.         return(-1);
  494.     }
  495.     row = (Uint8 *)dst->pixels+dstrect->y*dst->pitch+
  496.             dstrect->x*dst->format->BytesPerPixel;
  497.     if ( dst->format->palette || (color == 0) ) {
  498.         x = dstrect->w*dst->format->BytesPerPixel;
  499.         if ( !color && !((long)row&3) && !(x&3) && !(dst->pitch&3) ) {
  500.             int n = x >> 2;
  501.             for ( y=dstrect->h; y; --y ) {
  502.                 SDL_memset4(row, 0, n);
  503.                 row += dst->pitch;
  504.             }
  505.         } else {
  506. #ifdef __powerpc__
  507.             /*
  508.              * memset() on PPC (both glibc and codewarrior) uses
  509.              * the dcbz (Data Cache Block Zero) instruction, which
  510.              * causes an alignment exception if the destination is
  511.              * uncachable, so only use it on software surfaces
  512.              */
  513.             if((dst->flags & SDL_HWSURFACE) == SDL_HWSURFACE) {
  514.                 if(dstrect->w >= 8) {
  515.                     /*
  516.                      * 64-bit stores are probably most
  517.                      * efficient to uncached video memory
  518.                      */
  519.                     double fill;
  520.                     memset(&fill, color, (sizeof fill));
  521.                     for(y = dstrect->h; y; y--) {
  522.                         Uint8 *d = row;
  523.                         unsigned n = x;
  524.                         unsigned nn;
  525.                         Uint8 c = color;
  526.                         double f = fill;
  527.                         while((unsigned long)d
  528.                               & (sizeof(double) - 1)) {
  529.                             *d++ = c;
  530.                             n--;
  531.                         }
  532.                         nn = n / (sizeof(double) * 4);
  533.                         while(nn) {
  534.                             ((double *)d)[0] = f;
  535.                             ((double *)d)[1] = f;
  536.                             ((double *)d)[2] = f;
  537.                             ((double *)d)[3] = f;
  538.                             d += 4*sizeof(double);
  539.                             nn--;
  540.                         }
  541.                         n &= ~(sizeof(double) * 4 - 1);
  542.                         nn = n / sizeof(double);
  543.                         while(nn) {
  544.                             *(double *)d = f;
  545.                             d += sizeof(double);
  546.                             nn--;
  547.                         }
  548.                         n &= ~(sizeof(double) - 1);
  549.                         while(n) {
  550.                             *d++ = c;
  551.                             n--;
  552.                         }
  553.                         row += dst->pitch;
  554.                     }
  555.                 } else {
  556.                     /* narrow boxes */
  557.                     for(y = dstrect->h; y; y--) {
  558.                         Uint8 *d = row;
  559.                         Uint8 c = color;
  560.                         int n = x;
  561.                         while(n) {
  562.                             *d++ = c;
  563.                             n--;
  564.                         }
  565.                         row += dst->pitch;
  566.                     }
  567.                 }
  568.             } else
  569. #endif /* __powerpc__ */
  570.             {
  571.                 for(y = dstrect->h; y; y--) {
  572.                     memset(row, color, x);
  573.                     row += dst->pitch;
  574.                 }
  575.             }
  576.         }
  577.     } else {
  578.         switch (dst->format->BytesPerPixel) {
  579.             case 2:
  580.             for ( y=dstrect->h; y; --y ) {
  581.                 Uint16 *pixels = (Uint16 *)row;
  582.                 Uint16 c = color;
  583.                 Uint32 cc = (Uint32)c << 16 | c;
  584.                 int n = dstrect->w;
  585.                 if((unsigned long)pixels & 3) {
  586.                     *pixels++ = c;
  587.                     n--;
  588.                 }
  589.                 if(n >> 1)
  590.                     SDL_memset4(pixels, cc, n >> 1);
  591.                 if(n & 1)
  592.                     pixels[n - 1] = c;
  593.                 row += dst->pitch;
  594.             }
  595.             break;
  596.  
  597.             case 3:
  598.             if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
  599.                 color <<= 8;
  600.             for ( y=dstrect->h; y; --y ) {
  601.                 Uint8 *pixels = row;
  602.                 for ( x=dstrect->w; x; --x ) {
  603.                     memcpy(pixels, &color, 3);
  604.                     pixels += 3;
  605.                 }
  606.                 row += dst->pitch;
  607.             }
  608.             break;
  609.  
  610.             case 4:
  611.             for(y = dstrect->h; y; --y) {
  612.                 SDL_memset4(row, color, dstrect->w);
  613.                 row += dst->pitch;
  614.             }
  615.             break;
  616.         }
  617.     }
  618.     SDL_UnlockSurface(dst);
  619.  
  620.     /* We're done! */
  621.     return(0);
  622. }
  623.  
  624. /*
  625.  * Lock a surface to directly access the pixels
  626.  * -- Do not call this from any blit function, as SDL_DrawCursor() may recurse
  627.  *    Instead, use:
  628.  *    if ( (surface->flags & SDL_HWSURFACE) == SDL_HWSURFACE )
  629.  *               video->LockHWSurface(video, surface);
  630.  */
  631. int SDL_LockSurface (SDL_Surface *surface)
  632. {
  633.     if ( ! surface->locked ) {
  634.         /* Perform the lock */
  635.         if ( surface->flags & (SDL_HWSURFACE|SDL_ASYNCBLIT) ) {
  636.             SDL_VideoDevice *video = current_video;
  637.             SDL_VideoDevice *this  = current_video;
  638.             if ( video->LockHWSurface(this, surface) < 0 ) {
  639.                 return(-1);
  640.             }
  641.         }
  642.         if ( surface->flags & SDL_RLEACCEL ) {
  643.             SDL_UnRLESurface(surface, 1);
  644.             surface->flags |= SDL_RLEACCEL;    /* save accel'd state */
  645.         }
  646.         /* This needs to be done here in case pixels changes value */
  647.         surface->pixels = (Uint8 *)surface->pixels + surface->offset;
  648.     }
  649.  
  650.     /* Increment the surface lock count, for recursive locks */
  651.     ++surface->locked;
  652.  
  653.     /* Ready to go.. */
  654.     return(0);
  655. }
  656. /*
  657.  * Unlock a previously locked surface
  658.  * -- Do not call this from any blit function, as SDL_DrawCursor() may recurse
  659.  *    Instead, use:
  660.  *    if ( (surface->flags & SDL_HWSURFACE) == SDL_HWSURFACE )
  661.  *               video->UnlockHWSurface(video, surface);
  662.  */
  663. void SDL_UnlockSurface (SDL_Surface *surface)
  664. {
  665.     /* Only perform an unlock if we are locked */
  666.     if ( ! surface->locked || (--surface->locked > 0) ) {
  667.         return;
  668.     }
  669.  
  670.     /* Perform the unlock */
  671.     surface->pixels = (Uint8 *)surface->pixels - surface->offset;
  672.  
  673.     /* Unlock hardware or accelerated surfaces */
  674.     if ( surface->flags & (SDL_HWSURFACE|SDL_ASYNCBLIT) ) {
  675.         SDL_VideoDevice *video = current_video;
  676.         SDL_VideoDevice *this  = current_video;
  677.         video->UnlockHWSurface(this, surface);
  678.     } else {
  679.         /* Update RLE encoded surface with new data */
  680.         if ( (surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL ) {
  681.                 surface->flags &= ~SDL_RLEACCEL; /* stop lying */
  682.             SDL_RLESurface(surface);
  683.         }
  684.     }
  685. }
  686.  
  687. /* 
  688.  * Convert a surface into the specified pixel format.
  689.  */
  690. SDL_Surface * SDL_ConvertSurface (SDL_Surface *surface,
  691.                     SDL_PixelFormat *format, Uint32 flags)
  692. {
  693.     SDL_Surface *convert;
  694.     Uint32 colorkey = 0;
  695.     Uint8 alpha = 0;
  696.     Uint32 surface_flags;
  697.     SDL_Rect bounds;
  698.  
  699.     /* Check for empty destination palette! (results in empty image) */
  700.     if ( format->palette != NULL ) {
  701.         int i;
  702.         for ( i=0; i<format->palette->ncolors; ++i ) {
  703.             if ( (format->palette->colors[i].r != 0) ||
  704.                  (format->palette->colors[i].g != 0) ||
  705.                  (format->palette->colors[i].b != 0) )
  706.                 break;
  707.         }
  708.         if ( i == format->palette->ncolors ) {
  709.             SDL_SetError("Empty destination palette");
  710.             return(NULL);
  711.         }
  712.     }
  713.  
  714.     /* Create a new surface with the desired format */
  715.     convert = SDL_CreateRGBSurface(flags,
  716.                 surface->w, surface->h, format->BitsPerPixel,
  717.         format->Rmask, format->Gmask, format->Bmask, format->Amask);
  718.     if ( convert == NULL ) {
  719.         return(NULL);
  720.     }
  721.  
  722.     /* Copy the palette if any */
  723.     if ( format->palette && convert->format->palette ) {
  724.         memcpy(convert->format->palette->colors,
  725.                 format->palette->colors,
  726.                 format->palette->ncolors*sizeof(SDL_Color));
  727.         convert->format->palette->ncolors = format->palette->ncolors;
  728.     }
  729.  
  730.     /* Save the original surface color key and alpha */
  731.     surface_flags = surface->flags;
  732.     if ( (surface_flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY ) {
  733.         /* Convert colourkeyed surfaces to RGBA if requested */
  734.         if((flags & SDL_SRCCOLORKEY) != SDL_SRCCOLORKEY
  735.            && format->Amask) {
  736.             surface_flags &= ~SDL_SRCCOLORKEY;
  737.         } else {
  738.             colorkey = surface->format->colorkey;
  739.             SDL_SetColorKey(surface, 0, 0);
  740.         }
  741.     }
  742.     if ( (surface_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
  743.         alpha = surface->format->alpha;
  744.         SDL_SetAlpha(surface, 0, 0);
  745.     }
  746.  
  747.     /* Copy over the image data */
  748.     bounds.x = 0;
  749.     bounds.y = 0;
  750.     bounds.w = surface->w;
  751.     bounds.h = surface->h;
  752.     SDL_LowerBlit(surface, &bounds, convert, &bounds);
  753.  
  754.     /* Clean up the original surface, and update converted surface */
  755.     if ( convert != NULL ) {
  756.         SDL_SetClipRect(convert, &surface->clip_rect);
  757.     }
  758.     if ( (surface_flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY ) {
  759.         Uint32 cflags = surface_flags&(SDL_SRCCOLORKEY|SDL_RLEACCELOK);
  760.         if ( convert != NULL ) {
  761.             Uint8 keyR, keyG, keyB;
  762.  
  763.             SDL_GetRGB(colorkey,surface->format,&keyR,&keyG,&keyB);
  764.             SDL_SetColorKey(convert, cflags|(flags&SDL_RLEACCELOK),
  765.                 SDL_MapRGB(convert->format, keyR, keyG, keyB));
  766.         }
  767.         SDL_SetColorKey(surface, cflags, colorkey);
  768.     }
  769.     if ( (surface_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
  770.         Uint32 aflags = surface_flags&(SDL_SRCALPHA|SDL_RLEACCELOK);
  771.         if ( convert != NULL ) {
  772.                 SDL_SetAlpha(convert, aflags|(flags&SDL_RLEACCELOK),
  773.                 alpha);
  774.         }
  775.         SDL_SetAlpha(surface, aflags, alpha);
  776.     }
  777.  
  778.     /* We're ready to go! */
  779.     return(convert);
  780. }
  781.  
  782. /*
  783.  * Free a surface created by the above function.
  784.  */
  785. void SDL_FreeSurface (SDL_Surface *surface)
  786. {
  787.     /* Free anything that's not NULL, and not the screen surface */
  788.     if ((surface == NULL) ||
  789.         (current_video &&
  790.         ((surface == SDL_ShadowSurface)||(surface == SDL_VideoSurface)))) {
  791.         return;
  792.     }
  793.     if ( --surface->refcount > 0 ) {
  794.         return;
  795.     }
  796.     if ( (surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL ) {
  797.             SDL_UnRLESurface(surface, 0);
  798.     }
  799.     if ( surface->format ) {
  800.         SDL_FreeFormat(surface->format);
  801.         surface->format = NULL;
  802.     }
  803.     if ( surface->map != NULL ) {
  804.         SDL_FreeBlitMap(surface->map);
  805.         surface->map = NULL;
  806.     }
  807.     if ( (surface->flags & SDL_HWSURFACE) == SDL_HWSURFACE ) {
  808.         SDL_VideoDevice *video = current_video;
  809.         SDL_VideoDevice *this  = current_video;
  810.         video->FreeHWSurface(this, surface);
  811.     }
  812.     if ( surface->pixels &&
  813.          ((surface->flags & SDL_PREALLOC) != SDL_PREALLOC) ) {
  814.         free(surface->pixels);
  815.     }
  816.     free(surface);
  817. #ifdef CHECK_LEAKS
  818.     --surfaces_allocated;
  819. #endif
  820. }
  821.